#region Header File
//
// TrafficStats.cs - Computes statistics about data packet traffic
//
// Copyright (C) Javier Valcarce. BSD License
#endregion

#region Using Statements
using System;
using System.Threading;
#endregion

namespace Arq
{
	public interface ITrafficStats
	{
        long   PacketCount     { get; }
        long   ByteCount       { get; }
		double AvrPacketSize   { get; }
        double VarPacketSize   { get; }
		double InstantDataRate { get; }
        double AverageDataRate { get; }
	}
	
    /// <summary>
    /// Computes statistics about teletraffic 
    /// </summary>
	public class TrafficStats : ITrafficStats
    {
        /// <summary>
        /// Every RefreshRate milliseconds, the data rate estimators are updated.
        /// </summary>
        public const int RefreshRate = 250; 

        #region Private Members
        long     np;        // number of packets computed
        long     nt;        // number of time chunks of RefreshRate milliseconds elapsed
        long     tbc;       // total bit count 
        double   tdr;       // total data rate in bps
        long     sbc;       // slot bit count
        double   sdr;       // slot data rate in bps
        MeanVar  sz;        // mean/var of packet size in bits
        Timer    timer;
        object   sync = new object();

        #endregion


        #region Constructor
        public TrafficStats()
        {
            timer = new Timer(TimerTick, null, 0, RefreshRate);
            sz    = new MeanVar();

            Reset();
        }
        #endregion

        #region Private Methods
        void TimerTick(object state)
        {
            // this methods executes in a thread apart
            nt++;

            lock (sync)
            {
                tdr = (double) tbc / (RefreshRate * nt) * 1000;
                sdr = (double) sbc / (RefreshRate *  1) * 1000; 
                sbc = 0;
            }
        }
        #endregion

        #region Public Methods and Properties       
        /// <summary>
        /// Resets statistical counters
        /// </summary>
		public void Reset()
		{
            np    = 0;
            nt    = 0;
            tbc   = 0;
            tdr   = 0;
            sbc   = 0;
            sdr   = 0;

            sz.Reset();
		}


		/// <summary>
		/// Computes a new sample and updated statistical estimators
		/// </summary>
		/// <param name="size">packet's size in bits</param>
		public void NewPacket(int bitsize)
		{
            np++;

            lock (sync)
            {
                tbc += bitsize;
                sbc += bitsize;
            }

            sz.Compute(bitsize);
        }
        

		// Explicit implementation of ITrafficStats
        long   ITrafficStats.PacketCount     { get { return np;    } }
        long   ITrafficStats.ByteCount       { get { return tbc;   } }
        double ITrafficStats.AvrPacketSize   { get { return sz.Mean;     } }
        double ITrafficStats.VarPacketSize   { get { return sz.Variance; } }
        double ITrafficStats.InstantDataRate { get { return sdr;   } }
        double ITrafficStats.AverageDataRate { get { return tdr;   } }
		#endregion
	}
}
